package db

import (
	"github.com/boltdb/bolt"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/util/gconv"
	"time"
)

type boltDb struct {
	Bucket        string
	DbPath        string
	ErrorMsg      string
	unAutoClosure bool
	defKeyName    string
	db            *bolt.DB
	result        *gjson.Json
}

// 参数
type Options struct {
	Bucket        string
	DbPath        string
	UnAutoClosure bool
}

// BDb 获取数据库实例
func BDb(options ...Options) *boltDb {
	opt := Options{
		Bucket: "bolt_def_bucket",
		DbPath: "./frame/db/app.db",
	}
	if len(options) > 0 {
		opts := options[0]
		opt.UnAutoClosure = opts.UnAutoClosure
		if opts.Bucket != "" {
			opt.Bucket = opts.Bucket
		}
		if opts.DbPath != "" {
			opt.DbPath = opts.DbPath
		}
	}
	bdb := &boltDb{
		Bucket:        opt.Bucket,
		DbPath:        opt.DbPath,
		defKeyName:    "dbData",
		unAutoClosure: opt.UnAutoClosure,
	}
	//打开当前目录中的my.db数据文件。
	//如果不存在，将创建它。
	db, err := bolt.Open(bdb.DbPath, 0755, &bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		panic(err.Error())
	}
	_ = db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(bdb.Bucket))
		if err != nil {
			bdb.ErrorMsg = err.Error()
		}
		return err
	})
	bdb.db = db
	return bdb
}

// close 关闭数据库
func (bdb *boltDb) close() {
	if !bdb.unAutoClosure {
		_ = bdb.db.Close()
	}
}

// Set 关闭数据库
func (bdb *boltDb) Close() {
	_ = bdb.db.Close()
}

// Set 写入数据
func (bdb *boltDb) Set(key string, val interface{}) error {
	jsData := map[string]interface{}{
		bdb.defKeyName: val,
	}
	data, jsErr := gjson.New(jsData).ToJson()
	if jsErr != nil {
		return jsErr
	}
	err := bdb.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bdb.Bucket))
		err := b.Put([]byte(key), data)
		return err
	})
	defer bdb.close()
	return err
}

// Get 读取数据
func (bdb *boltDb) Get(key string) *boltDb {
	_ = bdb.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bdb.Bucket))
		v := b.Get([]byte(key))
		jsObj, err := gjson.LoadJson(v)
		if err != nil {
			return err
		}
		bdb.result = jsObj
		return nil
	})
	defer bdb.close()
	return bdb
}

// Json 直接返回json对象
func (bdb *boltDb) Json() *gjson.Json {
	data := bdb.result.Get(bdb.defKeyName)
	return gjson.New(data)
}

// Map 转map
func (bdb *boltDb) Map() map[string]interface{} {
	data := bdb.result.Get(bdb.defKeyName)
	return gjson.New(data).Map()
}

// String 转字符串
func (bdb *boltDb) String() string {
	data := bdb.result.Get(bdb.defKeyName)
	return gconv.String(data)
}

// Int 转字符串
func (bdb *boltDb) Int() int {
	data := bdb.result.Get(bdb.defKeyName)
	return gconv.Int(data)
}

// Int 转字符串
func (bdb *boltDb) Int64() int64 {
	data := bdb.result.Get(bdb.defKeyName)
	return gconv.Int64(data)
}
